
var bind=function(v,f){
	if(typeof(v)=='function'){
		v(f);
	}else{
		f(v);
	}
};
var bindIF=function(v,f){
	if(v!=undefined){
		bind(v,f);
	}
};
var bindMapIF=function(map,f){
	if(map){
		mb.Object.forEach(map, function(v,k){
			bind(v,function(newV){
				f(k,newV);
			});
		});
	}
};
/**
 * 是否要用id，造成手写DOM。如果用一点观察者模式，似乎会优化更多？通知中心，而不是全部用事件。本来想全用事件，但又离不开面向对象。事件就有内部的和外部的。
 * 事件绑定属性，还有初始化的。
 * 通知中心内聚成某个方法，但id还是显露被外部持有。但省掉了初始化构造。
 */
/*
功能不能太复杂了，或许是每次全部重新加载的模板。只作为原生的替换初始化的模板引擎函数。要实现复杂的，则自行加载其它自定义组件。
但动态增加组件，为了不触碰init，需要array的方法。
还是恢复ArrayModel，妥协的，解决大多数问题。
但要支持外部插件，如hover\select等扩展，而不写死在内部

用面向对象的方式，children是数组域，管理的就是控制器，不是数据与视图分离。数据与视图结合的控制器，就是自己的业务模型。有select。默认select与自定义（返回bool是否接受select）
数组管理的组件，有相应的与后端业务的更新方法。但insert是数据,remove是controller,move是顺序，不介入。
用自组件方式，不再反复显式调用parseEL，k也不再暴露在外。最初调用jsdom，以后加载自动都在其中，只是写配置。组件返回一个字典，me={k:{},init:{},public:{}}，public中是显式调用的。

不，children始终是依赖注入的slot，是注入实例不是注入类，不是Array数组。但这是针对扩展列表，不是原生的。只能实现初始化的mvc，不能实现动态的mvvm，未来要改变，只有重新reload。
所以不允许，可以用匿名生成数组为结果
*/

function bindId(me,id,obj){
	if(id){
		if(typeof(id)=='function'){
			id(obj);
		}else{
			me[id]=obj;
		}
	}
}
function parseEL(json,me){
	if(!json){
		json="";
	}
	var json_type=typeof(json);
	if(json_type=='function'){
		json=json();
	}else if(json_type!='object'){
		return document.createTextNode(json);
	}else{
		var el;
		var type=json.type;
		var children=json.children;
		var id=json.id;
		if(typeof(type)=='string'){
			el=document.createElement(type);
			bindId(me,id,el);
			if(children){
				if(mb.Array.isArray(children)){
					mb.Array.forEach(children,function(child,i){
						el.appendChild(parseEL(child,me));
					});
				}else
				if(typeof(children)=='function'){
					/**
					 * 子结点延迟可以异步加载，但其它属性节点有必要吗？
					 * 复杂点就是显式写mve.Watch(exp:)
					 */
					children(el);
				}else{
					var c_va=children.type(el,children.params);
					var c_id=children.id;
					bindId(me,c_id,c_va);
				}
			}
		}else{
			if(type){
				var params=json.params||{};
				if(children){
					mb.Object.forEach(children,function(value,key){
						params[key]=parseEL(value,me);
					});
				}
				var obj=type(params);
			}else if(json.jsdom){
				//自动注入的
				var obj=json.jsdom;
			}
			bindId(me,id,obj);
			if(obj.init){
				var init=me.init||mb.Function.quote.one;
				me.init=function() {
					obj.init();
					init();
				};
			}
			el=obj.element;
		}
		var actions=json.action;
		if(actions){
			mb.Object.forEach(actions,function(value:any,key){
				mb.DOM.addEvent(el,key,value);
			});
		}

		//类
		var cls=json.cls;
		if(cls){
			var type_cls=typeof(cls);
			if(type_cls=='object'){
				var cls_o=cls.type(el,cls.params);
				var cls_id=cls.id;
				if(cls_id){
					me.k[cls_id]=cls_o;
				}
			}else
			if(type_cls=='function'){
				cls(mb.DOM.cls(el));
			}else{
				el.setAttribute("class", cls);
			}
		}
		//attr
		bindMapIF(json.attr,function(key,value){
			el.setAttribute(key,value);
		});

		//style字典
		bindMapIF(json.style,function(key,value){
			try{
				el.style[key]=value;
			}catch(ex){
				mb.log(ex);
			}
		});

		//innerText
		bindIF(json.text,function(v){
			el.innerText=v;
		});
		
		//innerHTML
		bindIF(json.html,function(v){
			el.innerHTML=v;
		});
		
		//input等的value
		bindIF(json.value,function(v){
			el.value=v;
		});

		return el;
	}
};
const jsdom={
	/**
	 * 没办法面向对象化。
	 * 禁止转发，
	 * 从parseElement到new的跨度
	 */
	parseElement:function(json,me?) {
		me=me||{};
		me.k=me.k||{};
		var el=parseEL(json,me);
		me.element=el;
		return el;
	},
	parseFragment:function(json,me) {
		me=me||{};
		me.k=me.k||{};
		var fg=document.createDocumentFragment();
		for (var i = 0; i < json.length; i++) {
			fg.appendChild(parseEL(json[i],me));
		}
		return fg;
	},
	/** 
	 * 没有public方法的
	 * p{
	 * init:可选
	 * body:json
	 * }
	 */
	page:function(p){
		var me:any={};
		me.k={};
		me.init=p.init;
		me.element=parseEL(p.body,me);
		return me;
	},
	/**
	 * 参数里有
	 * 回调函数，
	 * 高阶类型，
	 * 电线（单独变化的值）数组（除电线外，有insert\remove等子信号）——数组是否需要？暂时不支持吧。
	 * 没有public方法，只返回一个元素，没有init方法，跟vue贴近。
	 * 其实jsdom.parseElement也支持，而且还附带public方法。
	 * 只是可以传电流了——这种优化
	 */
	circuit:function(json){
		
	}
};
export=jsdom;
